package lion.test;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import lion.dev.lang.MapJ;
import lion.framework.core.conf.Config;
import lion.framework.core.conf.ConfigManager;

/**
 * Scan and load class except inner class
 *
 * <pre>
 * time   2013年8月6日
 * mail   hl_0074@sina.com
 * </pre>
 *
 * @author lion
 */
public class ClassScanner {

	private List<Class<?>> classes = new ArrayList<>();
	private static Log log = LogFactory.getLog(ClassScanner.class);
	private List<String> configedPackages = new ArrayList<>();

	private static final String FRAMEWORK_BASE_PACKAGE = "lion";

	public ClassScanner(String path) {

		Config config = ConfigManager.getConfig("framework");

		List<MapJ> paths = config.getList("framework.package-scan");
		for (MapJ m : paths) {
			String p = m.getString("base");
			if (!configedPackages.contains(p)) {
				configedPackages.add(p);
			}
		}

		scan(path, "");
	}

	public List<Class<?>> getClasses() {

		return classes;
	}

	private void scan(String path, String basePkg) {

		File f = new File(path);
		if (f.isDirectory()) {
			for (File s : f.listFiles()) {
				String pkg = "";
				if (StringUtils.isBlank(basePkg)) {
					pkg = s.getName();
				} else {
					pkg = basePkg;
					if (s.isDirectory()) {
						pkg += "." + s.getName();
					}
				}
				scan(s.getPath(), pkg);
			}
		} else if (f.getName().endsWith(".jar")) {
			// 处理Jar文件
			JarFile jar = null;
			try {
				jar = new JarFile(f);
			} catch (Exception e) {
				if (log.isDebugEnabled()) {
					log.debug("error load jar:" + f.getName());
				}
			}
			if (jar == null) { return; }

			for (JarEntry je : Collections.list(jar.entries())) {
				addClass(je.getName().replace("/", "."));
			}
		} else {
			if (f.getName().indexOf("$") > -1) { return; }
			String classs = StringUtils.isBlank(basePkg) ? f.getName() : basePkg + "." + f.getName();
			addClass(classs);
		}
	}

	private void addClass(String clazz) {

		if (!clazz.endsWith(".class")) { return; }
		// add base scanner
		if (!basePackageMatches(clazz)) { return; }

		Class<?> c = null;

		try {
			c = Class.forName(clazz.substring(0, clazz.lastIndexOf(".")));
		} catch (Throwable e) {
			if (log.isDebugEnabled()) {
				log.debug(String.format("class [%s] load error for %s ", clazz, e.getMessage() + " not found"));
			}
		}
		if (c != null) {
			this.classes.add(c);
		}
	}

	private boolean basePackageMatches(String clazz) {

		if (clazz.indexOf("$") > -1) { return false; }
		if (clazz.startsWith(FRAMEWORK_BASE_PACKAGE)) { return true; }
		if (configedPackages == null || configedPackages.isEmpty()) { return false; }

		for (String prefix : configedPackages) {
			if (clazz.startsWith(prefix)) { return true; }
		}
		return false;
	}
}
